from collections.abc import Iterable
from typing import Any, List

from typing_inspect import get_args, get_origin
from zkl_pyutils_registries import UNSET

from zkl_pyutils_serialization.basics import get_context_tag_value
from zkl_pyutils_serialization.convert import convert, registry
from zkl_pyutils_serialization.convertors.common import PyObjectFormat
from zkl_pyutils_serialization.tags import DstFormat, DstTypehint, SrcFormat, SrcType
from .format import JsonValueFormat


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: Iterable, DstTypehint: list})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: Iterable, DstTypehint: list})
def list_convertor(items: list) -> list:
    dst_typehint = get_context_tag_value(DstTypehint)
    item_typehint = parse_list_type_args(dst_typehint)
    return [convert(item, dst_typehint=item_typehint) for item in items]


@registry.register({SrcFormat: PyObjectFormat, DstFormat: JsonValueFormat, SrcType: list})
@registry.register({SrcFormat: JsonValueFormat, DstFormat: PyObjectFormat, SrcType: list})
def list_convertor_passive(items: list) -> list:
    if get_context_tag_value(DstTypehint) not in (UNSET, Any):
        raise NotImplementedError
    return [convert(item) for item in items]


# utils


def parse_list_type_args(typehint: Any):
    origin = get_origin(typehint) or typehint
    origin = list if origin is List else origin
    if origin not in (list, Iterable):
        raise NotImplementedError

    args = get_args(typehint, evaluate=True)
    if len(args) == 0:
        item_typehint = UNSET
    elif len(args) == 1:
        item_typehint = args[0]
    else:
        raise TypeError(f"Invalid type args of {typehint}!")
    return item_typehint
